"""
====================================================================
MongoDB 工具模块 / MongoDB Utility Module
====================================================================
功能说明：
1. 提供全局MongoDB客户端实例和数据库连接
2. 使用连接池优化性能
3. 支持副本集和故障转移
4. 从环境变量读取连接配置（安全实践）

使用示例：
    from utils.mongo_util import db

    # 查询设备信息
    equipment = db.b_equipment_entity.find_one({"imei": "868..."})

    # 插入分析结果
    db.equipment_analysis.insert_one(analysis_data)

说明：
- client: MongoDB客户端实例（全局单例）
- db: 默认数据库实例（JBN_PRO）

作者: Data Analysis Team
日期: 2025-01-06
====================================================================
"""

import logging
from pymongo import MongoClient
from pymongo.errors import ConnectionFailure, ConfigurationError

# 导入配置
import config

# 配置日志记录器
logger = logging.getLogger(__name__)


def create_mongo_client() -> MongoClient:
    """
    创建MongoDB客户端实例

    返回:
        MongoClient: MongoDB客户端实例

    异常:
        ValueError: 当配置无效时
        ConnectionFailure: 当连接失败时

    配置说明：
    - 从 config.MONGODB_URI 读取连接字符串
    - 连接字符串包含认证信息、副本集等配置
    - 支持时区感知（tz_aware=True）
    - 使用连接池（maxPoolSize）提升性能
    - 定期心跳检测（heartbeatFrequencyMS）保持连接
    """
    try:
        # 从配置读取MongoDB URI
        mongo_uri = config.MONGODB_URI

        if not mongo_uri:
            raise ValueError(
                "❌ MongoDB连接URI未配置！\n"
                "请在 .env 文件中设置 MONGODB_URI 环境变量"
            )

        # 创建MongoDB客户端
        # 参数说明：
        # - mongo_uri: 连接字符串，包含主机、端口、数据库、认证、副本集等信息
        # - tz_aware: 启用时区感知，确保datetime对象包含时区信息
        # - maxPoolSize: 连接池最大连接数，提升并发性能
        # - serverSelectionTimeoutMS: 服务器选择超时（从config读取）
        # - heartbeatFrequencyMS: 心跳频率，定期检测副本集节点状态
        client = MongoClient(
            mongo_uri,
            tz_aware=True,  # 启用时区感知
            maxPoolSize=config.MONGODB_MAX_POOL_SIZE,  # 连接池大小
            serverSelectionTimeoutMS=config.MONGODB_SERVER_SELECTION_TIMEOUT_MS,  # 服务器选择超时
            heartbeatFrequencyMS=10000  # 每10秒心跳检测一次
        )

        # 测试连接（执行ping命令）
        # 这会触发实际的网络连接，确保配置正确
        client.admin.command('ping')

        logger.info("✅ MongoDB客户端连接成功")
        logger.info(f"📊 数据库: {config.MONGODB_DATABASE}")
        logger.info(f"🔗 连接池大小: {config.MONGODB_MAX_POOL_SIZE}")

        return client

    except ConfigurationError as e:
        error_msg = f"❌ MongoDB配置错误: {e}\n请检查 MONGODB_URI 配置是否正确"
        logger.error(error_msg)
        raise ValueError(error_msg)

    except ConnectionFailure as e:
        error_msg = (
            f"❌ MongoDB连接失败: {e}\n"
            "可能原因：\n"
            "1. MongoDB服务未启动\n"
            "2. 网络不通或防火墙阻止\n"
            "3. 认证信息错误\n"
            "4. 副本集配置错误"
        )
        logger.error(error_msg)
        raise ConnectionFailure(error_msg)

    except Exception as e:
        error_msg = f"❌ 创建MongoDB客户端时发生未知错误: {e}"
        logger.error(error_msg)
        raise


def get_database():
    """
    获取默认数据库实例

    返回:
        Database: MongoDB数据库实例

    说明：
    - 数据库名称从 config.MONGODB_DATABASE 读取
    - 返回的数据库对象可直接访问集合
    """
    db_name = config.MONGODB_DATABASE
    database = client[db_name]

    # 可选：验证数据库访问权限（通过list_collections测试）
    try:
        # 尝试列出集合（不会返回结果，只是测试权限）
        _ = database.list_collection_names(filter={"name": "test_permission"}, limit=1)
    except Exception as e:
        logger.warning(f"⚠️  数据库访问权限检查失败: {e}")

    return database


# ====================================================================
# 全局实例（模块级单例）
# ====================================================================

# 创建全局MongoDB客户端实例
# 说明：
# - 在模块导入时创建，整个应用共享同一个客户端
# - PyMongo客户端是线程安全的，可以在多线程环境中使用
# - 连接池会自动管理连接的创建和销毁
client = create_mongo_client()

# 获取默认数据库实例
# 说明：
# - db 是全局数据库对象，可在整个应用中使用
# - 通过 db.collection_name 访问集合
# - 例如: db.equipment_analysis, db.b_equipment_entity 等
db = get_database()


# ====================================================================
# 工具函数（可选）
# ====================================================================

def close_mongo_connection():
    """
    关闭MongoDB连接

    说明：
    - 通常在应用关闭时调用
    - FastAPI可以在shutdown事件中调用此函数
    - 会关闭所有连接池中的连接

    使用示例：
        @app.on_event("shutdown")
        async def shutdown_event():
            close_mongo_connection()
    """
    try:
        client.close()
        logger.info("✅ MongoDB连接已关闭")
    except Exception as e:
        logger.error(f"❌ 关闭MongoDB连接时出错: {e}")


def get_collection_names():
    """
    获取数据库中所有集合名称

    返回:
        List[str]: 集合名称列表

    说明：
    - 用于调试和管理
    - 可以查看数据库中有哪些集合可用
    """
    try:
        return db.list_collection_names()
    except Exception as e:
        logger.error(f"❌ 获取集合列表失败: {e}")
        return []


def check_connection_health() -> bool:
    """
    检查MongoDB连接健康状态

    返回:
        bool: 连接正常返回True，否则返回False

    说明：
    - 可用于健康检查端点
    - 执行ping命令验证连接
    """
    try:
        client.admin.command('ping')
        return True
    except Exception as e:
        logger.error(f"❌ MongoDB健康检查失败: {e}")
        return False


# ====================================================================
# 模块初始化检查
# ====================================================================

# 验证连接是否成功建立
if not check_connection_health():
    logger.warning(
        "⚠️  MongoDB初始连接检查失败！\n"
        "应用可能无法正常访问数据库，请检查配置和网络连接。"
    )
else:
    logger.info("✅ MongoDB模块初始化完成，连接健康")
